﻿using System;
using System.Diagnostics;
using System.Reflection;
using System.Web;

namespace KPIS.GERP.Models.Class
{
	/// <summary>
	/// Static use of Logging to Elmah, Use this with appropriate type of error or logging you are in need.
	/// Result will record to database and can be view on Webpage Gerp -> ErrorLog page
	/// Remark: uncaught error will store automatically
	/// </summary>
	public static class GerpLog
	{
		public static void Log(string message, int code = 0)
		{
			LogToElmah(new LogException(GetFormatStringError(message), code));
		}

		public static void Log(Exception e)
		{
			LogToElmah(e);
		}

		public static void Warning(string message, Exception innerException = null)
		{
			LogToElmah(new WarningException(GetFormatStringError(message), innerException));
		}

		public static void Error(string message, Exception innerException = null)
		{
			LogToElmah(new ErrorException(GetFormatStringError(message), innerException));
		}

		public static void Unknown(string message, Exception innerException = null)
		{
			LogToElmah(new UnknownException(GetFormatStringError(message), innerException));
		}

		public static void DatabaseException(string message, Exception innerException = null)
		{
			LogToElmah(new DataBaseException(GetFormatStringError(message), innerException));
		}

		public static void ApplicationException(string message, Exception innerException = null)
		{
			LogToElmah(new ApplicationException(GetFormatStringError(message), innerException));
		}

		public static void NullReferenceException(string message, Exception innerException = null)
		{
			LogToElmah(new NullReferenceException(GetFormatStringError(message), innerException));
		}

		public static void ArgumentNullException(string paramName, string message)
		{
			LogToElmah(new ArgumentNullException(paramName, GetFormatStringError(message)));
		}

		public static void InvalidOperationException(string message, Exception innerException = null)
		{
			LogToElmah(new InvalidOperationException(GetFormatStringError(message), innerException));
		}

		public static void WcfClientException(string message, string serviceName, Exception innerException = null)
		{
			LogToElmah(new WcfClientException(string.Format("Service \"{0}\"{1}{2}", serviceName, Environment.NewLine, GetFormatStringError(message)), innerException));
		}

		#region Misc Method

		public static string GetPreviousMethodName()
		{
			StackTrace stackTrace = new StackTrace();
			MethodBase methodBase4 = stackTrace.GetFrame(4).GetMethod();
			MethodBase methodBase3 = stackTrace.GetFrame(3).GetMethod();
			MethodBase methodBase2 = stackTrace.GetFrame(2).GetMethod();
			return string.Format("{2}/{1}/{0}", methodBase4, methodBase3, methodBase2);
		}

		public static string GetCallingMethod(string MethodAfter)
		{
			string str = "";
			try
			{
				StackTrace st = new StackTrace();
				StackFrame[] frames = st.GetFrames();
				for (int i = 0; i < st.FrameCount - 1; i++)
				{
					if (frames != null && frames[i].GetMethod().Name.Equals(MethodAfter))
					{
						if (!frames[i + 1].GetMethod().Name.Equals(MethodAfter)) // ignores overloaded methods.
						{
							str = frames[i + 1].GetMethod().ReflectedType.FullName + "." + frames[i + 1].GetMethod().Name;
							break;
						}
					}
				}
			}
			catch (Exception) { ; }
			return str;
		}

		private static void LogToElmah(Exception e)
		{
            try
            {
                Elmah.ErrorLog.GetDefault(HttpContext.Current).Log(new Elmah.Error(e, HttpContext.Current));
            } catch
            {
            }
		}

		public static string GetCurrentClassName()
		{
			StackFrame frame = new StackFrame(1);
			MethodBase method = frame.GetMethod();
			return method.DeclaringType != null ? method.DeclaringType.Name : string.Empty;
		}

		public static string GetFormatStringError(string message)
		{
			return string.Format("{0}{1}Custom error occur on {2}", message, Environment.NewLine, GetPreviousMethodName());
		}
		

		#endregion
	}

	/// <summary>
	/// The word before Exception will be show as Type in Report Elmah Error Log
	/// </summary>
	#region Custom Exception Object

	[Serializable]
	public class LogException : Exception
	{
		public LogException(string message, int code)
			: base(message)
		{ 
		}

		public LogException(string message, Exception innerException)
			: base(message, innerException)
		{
		}
		public LogException(string format, Exception innerException, params object[] args)
			: base(string.Format(format, args), innerException)
		{
		} 
	}

	[Serializable]
	public class WarningException : Exception
	{
		public WarningException(string message, int code)
			: base(message)
		{
		}

		public WarningException(string message, Exception innerException)
			: base(message, innerException)
		{
		}
		public WarningException(string format, Exception innerException, params object[] args)
			: base(string.Format(format, args), innerException)
		{
		}
	}

	[Serializable]
	public class ErrorException : Exception
	{
		public ErrorException(string message, int code)
			: base(message)
		{
		}

		public ErrorException(string message, Exception innerException)
			: base(message, innerException)
		{
		}
		public ErrorException(string format, Exception innerException, params object[] args)
			: base(string.Format(format, args), innerException)
		{
		}
	}

	[Serializable]
	public class UnknownException : Exception
	{
		public UnknownException(string message, int code)
			: base(message)
		{
		}

		public UnknownException(string message, Exception innerException)
			: base(message, innerException)
		{
		}
		public UnknownException(string format, Exception innerException, params object[] args)
			: base(string.Format(format, args), innerException)
		{
		}
	}

	[Serializable]
	public class DataBaseException : Exception
	{
		public DataBaseException(string message, int code)
			: base(message)
		{
		}

		public DataBaseException(string message, Exception innerException)
			: base(message, innerException)
		{
		}
		public DataBaseException(string format, Exception innerException, params object[] args)
			: base(string.Format(format, args), innerException)
		{
		}
	}

	[Serializable]
	public class WcfClientException : Exception
	{
		public WcfClientException(string message)
			: base(message)
		{
		}

		public WcfClientException(string message, Exception innerException)
			: base(message, innerException)
		{
		}
		public WcfClientException(string format, Exception innerException, params object[] args)
			: base(string.Format(format, args), innerException)
		{
		}
	}

	#endregion
}